#include "QWidget.h"
#include "spreadsheet.h"
#include "cell.h"
#include <QFile.h>
#include <QMessageBox.h>
#include <QApplication.h>
#include <QClipboard.h>

Spreadsheet::Spreadsheet(QWidget* parent)
	:QTableWidget(parent)
{
	autoRecalc = true;
	// 后面当用户编辑一个单元时，TableWidget使用此对象的clone方法创建新单元
	setItemPrototype(new Cell); 
	setSelectionMode(QAbstractItemView::ContiguousSelection);
	connect(this,SIGNAL(itemChanged(QTableWidgetItem*)),
		this,SLOT(somethingChanged()));
	clear();
}

Spreadsheet::Spreadsheet(int rows,int column,QWidget* parent)
	:QTableWidget(rows,column,parent)
{

}

Spreadsheet::~Spreadsheet()
{

}

QString Spreadsheet::currentLocation() const
{
	return QChar('A'+currentColumn())+QString::number(currentRow()+1);
}
QString Spreadsheet::currentFormula() const
{
	return formula(currentRow(),currentColumn());
}
QTableWidgetSelectionRange Spreadsheet::selectedRange() const
{
	QList<QTableWidgetSelectionRange> ranges = selectedRanges();
	if(ranges.isEmpty())
		return QTableWidgetSelectionRange();
	return ranges.first(); // 不支持多选，所以只返回第一个
}
void Spreadsheet::clear()
{
	setRowCount(0);
	setColumnCount(0);
	setRowCount(RowCount);
	setColumnCount(ColumnCount);

	for (int i = 0; i < ColumnCount; ++i) {
		QTableWidgetItem *item = new QTableWidgetItem;
		item->setText(QString(QChar('A' + i)));
		setHorizontalHeaderItem(i, item);
	}
	setCurrentCell(0, 0);
}

bool Spreadsheet::readFile(const QString& fileName)
{
	QFile file(fileName);
	if(!file.open(QIODevice::ReadOnly))
	{
		QMessageBox::warning(this,tr("spreadsheet"),
			tr("Cannot read file %1:\n%2.")
			.arg(file.fileName())
			.arg(file.errorString()));
		return false;
	}
	QDataStream in(&file);
	in.setVersion(QDataStream::Qt_5_0);
	quint32 magic;
	in >> magic;
	if(magic != MagicNumber)
	{
		QMessageBox::warning(this,tr("spreadsheet"),
			tr("The file is not a spreadsheet file."));
		return false;
	}
	clear();
	quint16 row;
	quint16 colum;
	QString str;
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	while(!in.atEnd())
	{
		in >> row >> colum >> str;
		setFormula(row,colum,str);
	}
	QApplication::restoreOverrideCursor();
	return true;
}
bool Spreadsheet::writeFile(const QString& fileName)
{
	QFile file(fileName);
	if(!file.open(QIODevice::WriteOnly))
	{
		QMessageBox::warning(this,tr("Spreadsheet"),
			tr("Cannot write file %1:\n%2.").arg(file.fileName()).arg(file.errorString()));
		return false;
	}
	QDataStream out(&file);
	out.setVersion(QDataStream::Qt_5_0);
	out << quint32(MagicNumber);
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	for(int row=0; row<RowCount; ++row)
	{
		for(int colum=0; colum<ColumnCount;++colum)
		{
			QString str = formula(row,colum);
			if(!str.isEmpty())
				out << quint16(row)<<quint16(colum)<<str;
		}
	}
	QApplication::restoreOverrideCursor();
	return true;
}
void Spreadsheet::sort(const SpreadsheetCompare& compare)
{

}

void Spreadsheet::cut()
{
	copy();
	del();
}
void Spreadsheet::copy()
{
	QTableWidgetSelectionRange range = selectedRange();
	QString str;
	for(int i=0; i<range.rowCount(); ++i)
	{
		if(i>0)
			str+="\n";
		for(int j=0; j<range.columnCount(); ++j)
		{
			if(j>0)
				str+="\t";
			str += formula(range.topRow()+i,range.leftColumn()+j);
		}
	}
	QApplication::clipboard()->setText(str);
}
void Spreadsheet::paste()
{

}
void Spreadsheet::del()
{

}
void Spreadsheet::selectCurrentRow()
{

}
void Spreadsheet::selectCurrentColumn()
{

}
void Spreadsheet::recalculate()
{

}
void Spreadsheet::findNext(const QString& str,Qt::CaseSensitivity cs)
{

}

Cell *Spreadsheet::cell(int row,int column) const
{
	return static_cast<Cell*>(item(row,column));
}
QString Spreadsheet::text(int row,int column) const
{
	Cell* c = cell(row,column);
	if(c)
		return c->text();
	else
		return "";
}
QString Spreadsheet::formula(int row,int column) const
{
	Cell* c = cell(row,column);
	if(c)
		return c->formula();
	else
		return "";
}
void Spreadsheet::setFormula(int row,int column,const QString& formula)
{
	Cell* c = cell(row,column);
	if(!c)
	{
		c = new Cell;
		setItem(row,column,c);
	}
	c->setFormula(formula);
}

void Spreadsheet::somethingChanged()
{
	if(autoRecalc)
		recalculate();
	emit modified();
}

